package club.xiaojiawei.array;

import java.util.Arrays;

/**
 * @author 肖嘉威
 * @version 1.0
 * @date 6/24/22 2:58 PM
 * @question 31. 下一个排列
 * @description 整数数组的一个 排列  就是将其所有成员以序列或线性顺序排列。
 * 例如，arr = [1,2,3] ，以下这些都可以视作 arr 的排列：[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。
 * 整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地，如果数组的所有排列根据其字典顺序从小到大排列在一个容器中，那么数组的 下一个排列 就是在这个有序容器中排在它后面的那个排列。如果不存在下一个更大的排列，那么这个数组必须重排为字典序最小的排列（即，其元素按升序排列）。
 * 例如，arr = [1,2,3] 的下一个排列是 [1,3,2] 。
 * 类似地，arr = [2,3,1] 的下一个排列是 [3,1,2] 。
 * 而 arr = [3,2,1] 的下一个排列是 [1,2,3] ，因为 [3,2,1] 不存在一个字典序更大的排列。
 * 给你一个整数数组 nums ，找出 nums 的下一个排列。
 * 必须 原地 修改，只允许使用额外常数空间。
 */
public class NextPermutation31 {

    public static void main(String[] args) {
        NextPermutation31 test = new NextPermutation31();
        int[] ints = {1,5,1};
        test.nextPermutation(ints);
        System.out.println(Arrays.toString(ints));
    }

    /**
     * 两遍扫描（可把我nb坏了）
     * 时间复杂度：O(N)
     * 空间复杂度：O(1)
     * @param nums
     */
    public void nextPermutation(int[] nums) {
        int l = nums.length;
        int temp;
        int i = l - 2;
//        从尾部开始寻找递增数组（从右往左看）折断处，即当前数小于后一个数的地方
        for (; i >= 0 ; i--){
            if (nums[i] < nums[i + 1]){
                break;
            }
        }
//        i=-1表示没找到，所以整个数组满足递减数组要求，直接反转整个数组即可
//        i!=-1表示找到了，所以在右边的递增子数组（从右往左看）中找到大于等于i下标处数字的最小值，然后将i处数字与其交换
        if (i != -1){
            for (int j = i + 2; j <= l; j++){
                if (j == l || nums[i] >= nums[j]){
                    temp = nums[j - 1];
                    nums[j - 1] = nums[i];
                    nums[i] = temp;
                    break;
                }
            }
        }
        i++;
        l--;
//        反转数组
        while (i < l){
            temp = nums[i];
            nums[i] = nums[l];
            nums[l] = temp;
            i++;
            l--;
        }
    }

}
